package de.uni_stuttgart.ipvs.ids.nameserver;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * TCPListener to listen for incoming TCP socket connections of recursive name resolutions.
 * @author Team 3/4 - Elkhan Dadashov, Dhaval A Shah, Patrick Stortz
 */
public class TCPListener extends Thread {

	/** The host address the TCPListener is running on. */
	private String hostAddress = "unknown";	
	/** The port the TCPListener is bound to */
	private int port;
	/** Reference to the Nameserver instance of this TCPListener */
	private Nameserver nameserver;

	/**
	 * Creates a TCPListener for a specific Nameserver with a specific port.
	 * Start the thread to bind the socket and listening for incoming connections (recursive resolution requests).
	 * @param nameserver The Nameserver instance using this TCPListener instance.
	 * @param port The port the TCPListener should listen to.
	 */
	public TCPListener(Nameserver nameserver, int port) {
		this.nameserver = nameserver;
		this.port = port;
		this.setName("TCPListener of " + nameserver.getDomain() + " @ " + nameserver.getAddress() + ":" + port);
		try {
			// try to get the IP address of this machine
			InetAddress ip = InetAddress.getLocalHost();
			this.hostAddress = ip.getHostAddress();
		} catch (UnknownHostException e) {
			this.hostAddress = "unknown";
		}
	}

	@Override
	public void run() {
		
		// bind the tcp socket
		ServerSocket socket = null;
		try {
			socket = new ServerSocket();
			socket.bind(new InetSocketAddress(this.port));
			System.out.println(getName() + " | Server socket bound at " + this.hostAddress + ":" + this.port + ".");// DEBUG LOG OUTPUT
		} catch (IOException e) {
			System.err.println(getName() + " | Could not bind the server socket! Exception: " + e.getMessage());// DEBUG LOG OUTPUT
			socket = null;
			return;
		}

		// loop and accept connections
		while (socket != null && (socket.isClosed() == false)) {
			try {
				// accept connection
				Socket parentSocket = socket.accept();
				// process the incoming connection
				this.nameserver.processRecursiveRequest(parentSocket);
			} catch (Exception e) {
				System.err.println(getName()+ " | Could not process a connection. Exception: " + e.getMessage());// DEBUG LOG OUTPUT
			}
		}

		// close the server socket
		if (socket != null && (socket.isClosed() == false)) {
			try {
				socket.close();
			} catch (IOException e) {
				System.err.println(getName() + " | Could not close the server socket! Exception: " + e.getMessage());// DEBUG LOG OUTPUT
			}
		}
		
		System.out.println(getName() + " | Thread finished.");
	}
}